﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Media;
namespace TrafficApp
{
    public class Car : Traffic
    {
        #region Vars

        //public static const int SIZE = 10;
        public const int TOPSPEED = 5;

        int carIndex;

        private enum decision
        {
            Left,
            Straight,
            Right
        }

        // private List<CarTL> TLs;
        private int distanceToTL()
        {
            Crossing cr = App.app.getCrossing(this.loc);
            return 42;
        }

        /// <summary>
        /// says if the car is in a transition (turn, lane shift)
        /// </summary>
        private bool transition = false;

        public Crossing Cross;

        /// <summary>
        /// this index makes sure we know which car is in front of us.
        /// </summary>
        private int frntIndex;

        /// <summary>
        /// which trafficlight the car should keep a look at.
        /// </summary>
        private int tlIndex;

        /// <summary>
        /// color of the car
        /// </summary>
        private Color clr;


        public Color Clr
        {
            get
            {
                return clr;
            }
        }

        /// <summary>
        /// on which section1 the car is
        /// </summary>
        private int lane;

        /// <summary>
        /// Path of the car
        /// </summary>
        private List<decision> path = new List<decision>();

        #endregion

        public Car(Vector cLocation, bool cShow, Vector cVelocity, int lane) : base(cLocation, cVelocity)
        {
            clr = chooseColor();
            createPath();
            carIndex = App.carIndex++;
        }

        private Color chooseColor()
        {
            Color c;
            int temp;
            temp = App.r.Next(1, 4);

            if (temp == 1)
            {                
                c = Color.FromArgb(255, 0, App.r.Next(151, 256), App.r.Next(0, 256));                
            }
            else if (temp == 2)
            {
                c = Color.FromArgb(255, App.r.Next(151, 256),0, App.r.Next(0, 256)); 
            }
            else
            {
                c = Color.FromArgb(255, App.r.Next(151, 256), App.r.Next(0, 256), 0); 
            }

            return c;
        }

        private void createPath()
        {
            //PositionChecker(Cross);

            if (loc.X % 180 > 60 && loc.X % 180 <= 80 && loc.Y % 180 >= 0 && loc.Y % 180 < 60) // top left (lane 1)
            {
                tlIndex = 0;                    
            }
            else if (loc.X % 180 > 80 && loc.X % 180 <= 100 && loc.Y % 180 >= 0 && loc.Y % 180 < 60) // top right (lane 2)
            {
                tlIndex = 1;                
            }
            else if (loc.X % 180 > 125 && loc.X % 180 <= 180 && loc.Y % 180 >= 60 && loc.Y % 180 < 80) // right top (lane 3)
            {
                tlIndex = 2;                
            }
            else if (loc.X % 180 > 125 && loc.X % 180 <= 180 && loc.Y % 180 >= 80 && loc.Y % 180 < 100) // right lower (lane 4)
            {
                tlIndex = 3;              
            }
            else if (loc.X % 180 > 100 && loc.X % 180 <= 120 && loc.Y % 180 >= 120 && loc.Y % 180 < 180) // lower right (lane 5)
            {
                tlIndex = 5;               
            }
            else if (loc.X % 180 > 80 && loc.X % 180 <= 100 && loc.Y % 180 >= 120 && loc.Y % 180 < 180) // lower left (lane 6)
            {
                tlIndex = 4;                
            }
            else if (loc.X % 180 < 60 && loc.X % 180 >= 0 && loc.Y % 180 >= 100 && loc.Y % 180 < 120) // left lower (lane 7)
            {
                tlIndex = 7;               
            }
            else if (loc.X % 180 < 60 && loc.X % 180 >= 0 && loc.Y % 180 >= 80 && loc.Y % 180 < 100) // left top (lane 8)
            {
                tlIndex = 6;               
            }

            if ((tlIndex == 0) || (tlIndex == 2) || (tlIndex == 5) || (tlIndex == 7))
            {
                path.Add((decision)1);
            }
            else if ((tlIndex == 1) || (tlIndex == 3) || (tlIndex == 4) || (tlIndex == 6))
            {
                path.Add((decision)0);
            }
            

                for (int i = 0; i < App.r.Next(4, 14); i++)
                {
                    path.Add((decision)App.r.Next(3));
                }
        }

        public List<Car> Move(List<Car> Cars)
        {
            // ********Algorithm priority list:********
            // * 1 check end of path.                 *
            // * 2 check end of road.                 *
            // * 3 check transition.                  *
            // *     3.1 check if transition done.    *
            // * 4 check front car (if any).          *
            // * 5 check distance TrafficLight        *
            // *     5.1 check TrafficLight state     *
            // ****************************************

            // Checks the car location on the crossing.
            int distance = PositionChecker(Cross);

            // If the path is finished.
            if (path.Count == 0)
            {
                Cars.Remove(this);
                return Cars;
            }
            else
            {
                // If the road is a dead end.
                if (Cross == null)
                {
                    Cars.Remove(this);
                    return Cars;
                }
                else
                {
                    #region Transition
                    // If the car is in a transition.
                    if (transition == true)
                    {
                        if (Cross.Type == "Cross1")
                        {
                            float temp;
                            switch (tlIndex)
                            {
                                case 0:
                                    if (path[0] == decision.Right)
                                    {
                                        if (loc.Y % 180 > 60)
                                        {
                                            velocity.Y = 0;
                                            velocity.X = -1;
                                            temp = loc.Y % 180;
                                            loc.Y -= temp;
                                            loc.Y += 64;
                                        }
                                        else if (loc.X % 180 < 1)
                                        {
                                            path.Remove(path[0]);
                                            transition = false;
                                        }
                                    }
                                    else if (path[0] == decision.Straight && loc.Y % 180 >= 179)
                                    {
                                        path.Remove(path[0]);
                                        transition = false;
                                    }
                                    break;

                                case 1:
                                    if (path[0] == decision.Left)
                                    {
                                        if (loc.Y % 180 >= 60 && velocity.X == 0 && loc.Y < 100)
                                        {
                                            temp = loc.Y % 180;
                                            loc.Y -= temp;
                                            loc.Y += 60;
                                            velocity.X = 26;
                                            velocity.Y = 46;
                                            
                                        }
                                        else if (loc.Y % 180 > 105)
                                        {
                                            velocity.X = 1;
                                            velocity.Y = 0;
                                            temp = loc.Y % 180;
                                            loc.Y -= temp;
                                            loc.Y += 105;
                                            path.Remove(path[0]);
                                        }
                                        else if (loc.X % 180 >= 179)
                                        {
                                            transition = false;
                                        }
                                    }
                                    break;

                                case 2:
                                    if (path[0] == decision.Right)
                                    {
                                        if (loc.Y % 180 > 60)
                                        {
                                            velocity.Y = 0;
                                            velocity.X = -1;
                                            temp = loc.Y % 180;
                                            loc.Y -= temp;
                                            loc.Y += 64;
                                        }
                                        else if (loc.X % 180 < 1)
                                        {
                                            path.Remove(path[0]);
                                            transition = false;
                                        }
                                    }
                                    else if (path[0] == decision.Straight && loc.Y % 180 < 1)
                                    {
                                        path.Remove(path[0]);
                                        transition = false;
                                    }
                                    break;

                                case 3:
                                    if (path[0] == decision.Left)
                                    {
                                        if (loc.X % 180 <= 105 && velocity.Y == 0)
                                        {
                                            temp = loc.X % 180;
                                            loc.X -= temp;
                                            loc.X += 105;
                                            velocity.X = -41;
                                            velocity.Y = 21;

                                        }
                                        else if (loc.Y % 180 > 106)
                                        {
                                            velocity.X = 0;
                                            velocity.Y = 1;
                                            temp = loc.Y % 180;
                                            loc.Y -= temp;
                                            loc.Y += 105;
                                            path.Remove(path[0]);
                                        }
                                        else if (loc.X % 180 >= 179)
                                        {
                                            transition = false;
                                        }
                                    }
                                    break;

                                case 4:
                                    if (path[0] == decision.Left)
                                    {
                                        if (loc.Y % 180 <= 105 && velocity.X == 0 && loc.Y > 66)
                                        {
                                            temp = loc.Y % 180;
                                            loc.Y -= temp;
                                            loc.Y += 105;
                                            velocity.X = -26;
                                            velocity.Y = -46;

                                        }
                                        else if (loc.Y % 180 < 64)
                                        {
                                            velocity.X = -1;
                                            velocity.Y = 0;
                                            temp = loc.Y % 180;
                                            loc.Y -= temp;
                                            loc.Y += 64;
                                            path.Remove(path[0]);
                                        }
                                    }
                                    break;

                                case 5:

                                    break;

                                case 6:
                                    if (path[0] == decision.Left)
                                    {
                                        if (loc.X % 180 >= 65 && velocity.Y == 0)
                                        {
                                            temp = loc.X % 180;
                                            loc.X -= temp;
                                            loc.X += 65;
                                            velocity.X = 46;
                                            velocity.Y = -26;

                                        }
                                        else if (loc.Y % 180 < 60)
                                        {
                                            velocity.X = 0;
                                            velocity.Y = -1;
                                            temp = loc.Y % 180;
                                            loc.Y -= temp;
                                            loc.Y += 65;
                                            path.Remove(path[0]);
                                        }
                                        else if (loc.Y % 180 <= 1)
                                        {
                                            transition = false;
                                        }
                                    }
                                    break;

                                case 7:

                                    break;
                            }
                        }
                        // crossing type 2.
                        else
                        {
                        }
                    }
                    #endregion
                    else
                    {
                        
                        if (speed <= TOPSPEED && !transition)
                        {
                            speed++;
                        }
                        else if (speed > TOPSPEED && !transition)
                        {
                            speed = TOPSPEED;
                        }
                        // check distance to front car.
                        float temp = distanceToCarInFront(Cars);
                        try
                        {
                            ColAdjuster(Cars[frntIndex], temp);
                        }
                        catch
                        {
                        }
                        if (Cross != null)
                        {
                            if (Cross.Carlights[tlIndex].Clr == Color.Red && distance <= 10) //need to check if car is in transition here, if it is it should be allowed to finish 
                            {
                                speed = 0;
                            }
                            else if (distance > 0 && distance < 10)
                            {
                                transition = true;
                            }
                        }
                        // TODO: add behavior logic.
                    }
                }
            }
            if (speed != 0)
            {
                velocity.Normalize();
                velocity.Multiply(speed);
                loc.X += velocity.X;
                loc.Y += velocity.Y;
            }
            return Cars;
        }

        private float distanceToCarInFront(List<Car> Cars)
        {
            float tempX;
            float tempY;
            float holder = 0;
            int indexHolder = -1;

            for (int i = 0; i < Cars.Count; i++)
            {
                if (Cars[i] != this)
                {
                    if (Cars[i].lane == this.lane)
                    {
                        if (this.velocity.X > 0)
                        {
                            if (this.loc.X < Cars[i].loc.X)
                            {
                                tempX = Cars[i].loc.X - this.loc.X;
                                if (holder != 0 && holder > tempX)
                                {
                                    holder = tempX;
                                    indexHolder = i;
                                }
                            }
                        }
                        else if (this.velocity.X < 0)
                        {
                            if (this.loc.X > Cars[i].loc.X)
                            {
                                tempX = Cars[i].loc.X - this.loc.X;
                                if (holder != 0 && holder > tempX)
                                {
                                    holder = tempX;
                                    indexHolder = i;
                                }
                            }
                        }
                        else if (this.velocity.Y > 0)
                        {
                            if (this.loc.Y < Cars[i].loc.Y)
                            {
                                tempY = Cars[i].loc.Y - this.loc.Y;
                                if (holder != 0 && holder > tempY)
                                {
                                    holder = tempY;
                                    indexHolder = i;
                                }
                            }
                        }
                        else if (this.velocity.Y < 0)
                        {
                            if (this.loc.Y > Cars[i].loc.Y)
                            {
                                tempY = Cars[i].loc.Y - this.loc.Y;
                                if (holder != 0 && holder > tempY)
                                {
                                    holder = tempY;
                                    indexHolder = i;
                                }
                            }
                        }
                        else
                        {
                            holder = -1;
                        }
                    }
                }
            }
            frntIndex = indexHolder;
            return holder;
        }

        /// <summary>
        /// adjusts speed of a car according to next car.
        /// </summary>
        /// <param name="frntCar">car in front</param>
        /// <param name="distance">distance to front car</param>
        private void ColAdjuster(Car frntCar, float distance)
        {
            if (frntIndex < 0 & distance + frntCar.speed <= this.speed * 1.5)
            {
                if (this.speed != frntCar.speed)
                {
                    speed--;
                }
            }
        }

        /// <summary>
        /// checks on which road the car is of an arbitrary crossing
        /// </summary>
        private int PositionChecker(Crossing cr)
        {
            int temp;
            if (cr == null)
            {
                return -1;
            }
            else if (cr.Type == "Cross1")
            {
                int locX = (int)loc.X % 180;
                int locY = (int)loc.Y % 180;

                if (locX > 60 && locX <= 80 && locY >= 0 && locY < 60 && !transition) // top left (lane 1)
                {
                    tlIndex = 0;
                    temp = (int)(Crossing.NORTH_Y1 - ((this.loc.Y + 10) % 180));
                    return temp;
                }
                else if (locX > 80 && locX <= 100 && locY >= 0 && locY < 60 && !transition) // top right (lane 2)
                {
                    tlIndex = 1;
                    temp = (int)(Crossing.NORTH_Y1 - ((this.loc.Y + 10) % 180));
                    return temp;
                }
                else if (locX > 125 && locX <= 180 && locY >= 60 && locY < 80 && !transition) // right top (lane 3)
                {
                    tlIndex = 2;
                    temp = 1 * ((int)((this.loc.X) % 180)) - (Crossing.EAST_X1);
                    return temp;
                }
                else if (locX > 125 && locX <= 180 && locY >= 80 && locY < 100 && !transition) // right lower (lane 4)
                {
                    tlIndex = 3;
                    temp = 1 * ((int)((this.loc.X) % 180)) - (Crossing.EAST_X1);
                    return temp;
                }
                else if (locX > 100 && locX <= 120 && locY >= 120 && locY < 180 && !transition) // lower right (lane 5)
                {
                    tlIndex = 5;
                    temp = (int)(((this.loc.Y) % 180) - Crossing.SOUTH_Y1 );
                    return temp;
                }
                else if (locX > 80 && locX <= 100 && locY >= 120 && locY < 180 && !transition) // lower left (lane 6)
                {
                    tlIndex = 4;
                    temp = (int)(((this.loc.Y) % 180) - Crossing.SOUTH_Y1);
                    return temp;
                }
                else if (locX < 60 && locX >= 0 && locY >= 100 && locY < 120 && !transition) // left lower (lane 7)
                {
                    tlIndex = 7;
                    temp = (int)(Crossing.WEST_X1 - ((this.loc.X + 10) % 180));
                    return temp;
                }
                else if (locX < 60 && locX >= 0 && locY >= 80 && locY < 100 && !transition) // left top (lane 8)
                {
                    tlIndex = 6;
                    temp = (int)(Crossing.WEST_X1 - ((this.loc.X + 10) % 180));
                    return temp;
                }
            }
                /*
            else
            {
                if (loc.X < 90 && locY < 60)
                {
                }
                else if (true)
                {
                }
                else if (true)
                {
                }
                else if (true)
                {
                }
            }*/
            return -1;
        }
    }
}
